home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / 第1特集Plug-in / Photoshop / Marhil plugin 1.4.sit / Marhil plugin 1.4 / Source Code / mh.c < prev    next >
Text File  |  1994-02-16  |  15KB  |  577 lines

  1. /*
  2.     File: mh.c
  3.  
  4.     Copyright 1999 by Ralph Pugmire
  5.  
  6.     Marr Hildreth Edge detection filter
  7. */
  8.  
  9. #include <SetUpA4.h>
  10. #include "FilterInterface.h"
  11. #include "Utilities.h"
  12. #include "mh.h"
  13. #include "math.h"
  14. #include <stdlib.h>
  15.  
  16. #define Length(string) (*(unsigned char *)(string))
  17.  
  18. typedef struct TParameters{
  19.     int        wsize;
  20.     Boolean    sbsflag,mtflag;
  21.     double     sigma, zband, total;
  22. } TParameters, *PParameters, **HParameters;
  23.  
  24. short             gResult;
  25. FilterRecordPtr gStuff;
  26. int                mx,my,wsize,
  27.                 midx,midy,    /* offset to middle of convolving mask */
  28.                 xmax,ymax,
  29.                 nxmax,nymax;
  30.  
  31. Boolean         sbsflag,mtflag;
  32. double             sigma,
  33.                 zband, 
  34.                 total;
  35. imgdr             c_img, m_img;
  36. imgd             i_img,o_img;    /* pointer to my style image descriptor */
  37.  
  38. /*****************************************************************************/
  39. /* My routines*/
  40. double calctotal(Boolean mtflag){
  41. int    
  42.     x,y;
  43. double
  44.     zoffset,dtotal,
  45.     dsigma,        /* sigma as double */
  46.     rs,            /* distance from centre of mask*/
  47.     pis4,        /* 1/pi s^4 */
  48.     ro2s,        /* r^2 / 2sigma^2 */
  49.     midx,midy;        /* middle of mask */
  50.     
  51.     midx = (m_img.x - 1)/2.0;
  52.     midy = (m_img.y - 1)/2.0;
  53.     dsigma = sigma;
  54.     pis4 = 1.0 / 3.14159 / pow(dsigma,4.0);
  55.     
  56.     for (y=dtotal=0; y<m_img.y; y++){
  57.         for (x=0; x<m_img.x; x++){
  58.             rs = (midx-x)*(midx-x) + (midy-y)*(midy-y);
  59.             ro2s = rs / 2 / dsigma / dsigma;
  60.             m_img.e[y][x] = 10 * pis4 * (1.0 - ro2s) * exp(-ro2s);
  61.             dtotal += m_img.e[y][x] ;
  62.         }
  63.     }
  64.     if(mtflag){
  65.         zoffset = (dtotal) / wsize / wsize;
  66.         for (y=dtotal=0; y<m_img.y; y++){
  67.             for (x=0; x<m_img.x; x++){
  68.                 m_img.e[y][x] -= zoffset;
  69.                 dtotal += m_img.e[y][x] ;
  70.             }
  71.         }
  72.     }         
  73.     return dtotal;
  74. }
  75.  
  76. /*****************************************************************************/
  77.  
  78. /* Calls the host's TestAbort function */
  79.  
  80. Boolean TestAbort (void){
  81.     return CallPascalB (gStuff->abortProc);
  82.     }
  83.  
  84. /*****************************************************************************/
  85.  
  86. /* Calls the host's UpdateProgress procedure */
  87.  
  88. void UpdateProgress (long done, long total){
  89.     CallPascal (done, total, gStuff->progressProc);
  90.     }
  91.  
  92. /*****************************************************************************/
  93.  
  94. /* Centers a dialog template 1/3 of the way down on the main screen. */
  95.  
  96. #define menuHeight 20
  97. void CenterDialog (DialogTHndl dt){
  98.     Rect r;
  99.     short width;
  100.     short height;
  101.  
  102.     width  = screenBits.bounds.right;
  103.     height = screenBits.bounds.bottom;
  104.  
  105.     r = (**dt).boundsRect;
  106.     OffsetRect (&r, -r.left, -r.top);
  107.     OffsetRect (&r, (width - r.right) / 2,
  108.                     (height - r.bottom - menuHeight) / 3 + menuHeight);
  109.     (**dt).boundsRect = r;
  110.     }
  111.  
  112. #undef menuHeight
  113.  
  114. /*****************************************************************************/
  115.  
  116. /* Displays the about dialog box for the plug-in module. */
  117.  
  118. void DoAbout (void){
  119.     short item;
  120.     DialogPtr dp;
  121.     DialogTHndl dt;
  122.  
  123.     dt = (DialogTHndl) GetResource ('DLOG', AboutdialogID);
  124.     HNoPurge ((Handle) dt);
  125.     CenterDialog (dt);
  126.  
  127.     dp = GetNewDialog (AboutdialogID, nil, (WindowPtr) -1);
  128.  
  129.     ModalDialog (nil, &item);
  130.  
  131.     DisposDialog (dp);
  132.     HPurge ((Handle) dt);
  133.     }
  134.  
  135. #undef dialogID
  136.  
  137. /*****************************************************************************/
  138.  
  139. /* UserItem to outline the OK button in a dialog box. */
  140.  
  141. pascal void OutlineOK (DialogPtr dp, short item){
  142.     Rect r;
  143.     Handle h;
  144.     short itemType;
  145.     
  146.     SetUpA4 ();
  147.  
  148.     item = OK;
  149.  
  150.     GetDItem (dp, item, &itemType, &h, &r);
  151.  
  152.     PenNormal ();
  153.     PenSize (3, 3);
  154.     
  155.     InsetRect (&r, -4, -4);
  156.     FrameRoundRect (&r, 16, 16);
  157.  
  158.     PenNormal ();
  159.     
  160.     RestoreA4 ();
  161.     }
  162.  
  163. /*****************************************************************************/
  164.  
  165. /* Asks the user for the plug-in filter module's parameters. Note that
  166.    the image size information is not yet defined at this point. Also, do
  167.    not assume that the calling program will call this routine every time the
  168.    filter is run (it may save the data held by the parameters handle in
  169.    a macro file). */
  170.  
  171.  
  172. void DoParameters (void){
  173.     Rect r;
  174.     short j;
  175.     Str255 s;
  176.     unsigned char *p, *pp;
  177.     Handle h;
  178.     short item;
  179.     DialogPtr dp;
  180.     short itemType;
  181.     DialogTHndl dt;
  182.     int x,y;
  183.     float prevtotal;
  184.     Boolean afterpeak;
  185.     
  186.     if (!gStuff->parameters)
  187.         {
  188.         gStuff->parameters = NewHandle ((long) sizeof (TParameters));
  189.  
  190.         if (!gStuff->parameters)
  191.             {
  192.             gResult = memFullErr;
  193.             return;
  194.             }
  195.  
  196.         ((PParameters) *gStuff->parameters)->sigma = 1.2;
  197.         ((PParameters) *gStuff->parameters)->zband = 0.01;
  198.         ((PParameters) *gStuff->parameters)->total = 0.0;
  199.         ((PParameters) *gStuff->parameters)->wsize = 11;
  200.         ((PParameters) *gStuff->parameters)->mtflag = false;
  201.         ((PParameters) *gStuff->parameters)->sbsflag = true;
  202.         }
  203.  
  204.     dt = (DialogTHndl) GetResource ('DLOG', ParamsdialogID);
  205.     HNoPurge ((Handle) dt);
  206.     CenterDialog (dt);
  207.  
  208.     dp = GetNewDialog (ParamsdialogID, nil, (WindowPtr) -1);
  209.     
  210.     RememberA4 ();
  211.  
  212.     GetDItem (dp, hookItem, &itemType, &h                  , &r);
  213.     SetDItem (dp, hookItem,  itemType, (Handle) &OutlineOK, &r);
  214.  
  215.     sigma = ((PParameters) *gStuff->parameters)->sigma;
  216.     zband = ((PParameters) *gStuff->parameters)->zband;
  217.     wsize = ((PParameters) *gStuff->parameters)->wsize;
  218.     mtflag = ((PParameters) *gStuff->parameters)->mtflag;
  219.     sbsflag = ((PParameters) *gStuff->parameters)->sbsflag;
  220.     gResult = dimimgr(&m_img,wsize,wsize); /* create and init mask image */
  221.     if (gResult != noErr) return;
  222.     total = calctotal(mtflag);
  223.     freeimgr(&m_img);
  224.     
  225.     SetDReal(dp,sigmaItem,sigma,2);
  226.     SetDReal(dp,zbandItem,zband,3);
  227.     SetDReal(dp,totalItem,total,6);
  228.     SetDNum(dp,wsizeItem,wsize);
  229.     SetDialogItem(dp,mtflagItem,mtflag);
  230.     SetDialogItem(dp,sbsflagItem,sbsflag);
  231.     SelIText (dp, sigmaItem, 0, 32767);
  232.     do{
  233.  
  234.         ModalDialog (nil, &item);
  235.  
  236.         switch (item){
  237.         case wsizeItem:
  238.             /* Beep and remove anything other than 0-9 */
  239.             GetDString(dp,wsizeItem,s);
  240.             for (p=s+1; p<=s+s[0]; p++){
  241.                 if (*p>'9' || *p<'0'){
  242.                     SysBeep(1);
  243.                     s[0]--;
  244.                     for (pp=p; pp<=s+s[0]; pp++)
  245.                         *pp = *(pp+1);
  246.                 }
  247.                 SetDString(dp,wsizeItem,s);
  248.             }
  249.             break;
  250.         case calcwsizeItem:
  251.             //Find odd value for which total is less than 0.01 after reached a max
  252.             sigma = GetDReal(dp,sigmaItem);
  253.             afterpeak = false;
  254.             for (wsize=3; wsize<25; wsize += 2){
  255.                 SetDNum(dp,wsizeItem,wsize);
  256.                 gResult = dimimgr(&m_img,wsize,wsize); /* create and init mask image */
  257.                 if (gResult != noErr) return;
  258.                 total = calctotal(false);
  259.                 SetDReal(dp,totalItem,total,6);
  260.                 freeimgr(&m_img);
  261.                 if (total<prevtotal)  afterpeak=true;
  262.                 if ((total<0.01) && afterpeak) break;
  263.                 prevtotal = total;
  264.             }
  265.             gResult = dimimgr(&m_img,wsize,wsize); /* create and init mask image */
  266.             if (gResult != noErr) return;
  267.             total = calctotal(mtflag);
  268.             SetDReal(dp,totalItem,total,6);
  269.             freeimgr(&m_img);
  270.             break;
  271.             
  272.         case sbsflagItem:
  273.             sbsflag = !sbsflag;
  274.             SetDialogItem(dp,sbsflagItem,sbsflag);
  275.             break;
  276.             
  277.         case mtflagItem:
  278.             mtflag = !mtflag;
  279.             SetDialogItem(dp,mtflagItem,mtflag);
  280.             if (!mtflag)
  281.                 SelIText (dp, zbandItem, 0, 32767);
  282.             else
  283.                 SelIText (dp, sigmaItem, 0, 32767);
  284.             // Then fall into calcItem    
  285.  
  286.         case calcItem:
  287.             sigma = GetDReal(dp,sigmaItem);
  288.             wsize = GetDNum(dp,wsizeItem);
  289.             gResult = dimimgr(&m_img,wsize,wsize); /* create and init mask image */
  290.             if (gResult != noErr) return;
  291.             total = calctotal(mtflag);
  292.             SetDReal(dp,totalItem,total,6);
  293.             freeimgr(&m_img);
  294.             break;
  295.         }
  296.     }while (item != OK && item != Cancel);
  297.  
  298.     if (item == OK){
  299.         sigma = GetDReal(dp,sigmaItem);
  300.         wsize = GetDNum(dp,wsizeItem);
  301.         zband = GetDReal(dp,zbandItem);
  302.         ((PParameters) *gStuff->parameters)->sigma = sigma;
  303.         ((PParameters) *gStuff->parameters)->zband = zband;
  304.         ((PParameters) *gStuff->parameters)->total = total;
  305.         ((PParameters) *gStuff->parameters)->wsize = wsize;
  306.         ((PParameters) *gStuff->parameters)->mtflag = mtflag;
  307.         ((PParameters) *gStuff->parameters)->sbsflag = sbsflag;
  308.     } 
  309.  
  310.     DisposDialog (dp);
  311.     HPurge ((Handle) dt);
  312.  
  313.     if (item == Cancel){
  314.         gResult = 1;
  315.         return;
  316.     }
  317.  
  318. }
  319. #undef dialogID
  320. #undef hookItem
  321.  
  322. /*****************************************************************************/
  323.  
  324. /* Prepare to filter an image.    If the plug-in filter needs a large amount
  325.    of buffer memory, this routine should set the bufferSpace field to the
  326.    number of bytes required. */
  327.  
  328. void DoPrepare (void){
  329.     typedef short double *psdouble;
  330.     double zoffset;
  331.     int i,x,y;
  332.     unsigned char 
  333.          *ptr;
  334.  
  335.     sigma = ((PParameters) *gStuff->parameters)->sigma;
  336.     zband = ((PParameters) *gStuff->parameters)->zband;
  337.     wsize = ((PParameters) *gStuff->parameters)->wsize;
  338.     mtflag = ((PParameters) *gStuff->parameters)->mtflag;
  339.     sbsflag = ((PParameters) *gStuff->parameters)->sbsflag;
  340.  
  341.     my = gStuff->filterRect.bottom - gStuff->filterRect.top + 1;
  342.     mx = gStuff->filterRect.right - gStuff->filterRect.left + 1;
  343.     xmax = mx - wsize + 1;
  344.     ymax = my - wsize + 1;
  345.     midx = (wsize - 1)/2.0;
  346.     midy = (wsize - 1)/2.0;
  347.     nxmax = mx - midx -1;
  348.     nymax = my - midy -1;
  349.  
  350. /* tell them how much space we want */
  351.     gStuff->bufferSpace =     (long)wsize * wsize * sizeof(short double) 
  352.                             + (long)wsize * sizeof(psdouble)
  353.                             +(long)mx * my * sizeof(short double) 
  354.                             + (long)my * sizeof(psdouble);
  355.  
  356. }
  357.  
  358. /*****************************************************************************/
  359.  
  360. /* Requests pointer to the first part of the image to be filtered. */
  361. /* Lets try asking for all the image in one go */
  362. void DoStart (void){
  363.     
  364.     gResult = dimimgr(&c_img,my,mx); /* create and init real conv img*/
  365.     if (gResult != noErr) return;
  366.  
  367.     gResult = dimimgr(&m_img,wsize,wsize); /* create and init kernel image */
  368.     if (gResult != noErr){
  369.         freeimgr(&c_img);
  370.          return;
  371.      }
  372.     
  373.     total = calctotal(mtflag);
  374.  
  375.     gStuff->inRect = gStuff->filterRect;
  376.  
  377.     gStuff->inLoPlane = 0;
  378.     
  379.     switch (gStuff->imageMode){
  380.         case filterModeGrayScale:
  381.             gStuff->inHiPlane = 0;
  382.             break;
  383.         default:
  384.             gResult = filterBadMode;
  385.     }
  386.  
  387.     gStuff->outRect = gStuff->inRect;
  388.     gStuff->outLoPlane = gStuff->inLoPlane;
  389.     gStuff->outHiPlane = gStuff->inHiPlane;
  390. }
  391.  
  392. /*****************************************************************************/
  393.  
  394. /* Filters the area and requests the next area. */
  395.  
  396. void DoContinue (void){
  397. /* convolve with input image */
  398. #define max(a,b) ((a>b) ? (a) : (b))
  399. #define min(a,b) ((a<b) ? (a) : (b))
  400.     int 
  401.         i,d,x,y,sj,j,jj;
  402.     short double
  403.         *re,smin,smax,cmin,cmax;
  404.     short double
  405.         c,mzband;
  406.     unsigned char
  407.         *tpe,*pe,*ptr;
  408.  
  409.     /*convert the input and output roi's to my style images*/
  410.     i_img.y = my;
  411.     i_img.x = mx;
  412.     if (!(i_img.e = (ppc)NewPtr(sizeof(ptr) * my))){
  413.         gResult = memFullErr; return;}
  414.     ptr=(unsigned char *) gStuff->inData;
  415.     for (i=0; i<my; i++){
  416.         i_img.e[i] = ptr;
  417.         ptr += gStuff->inRowBytes;
  418.     }
  419.     o_img.y = my;
  420.     o_img.x = mx;
  421.     if (!(o_img.e = (unsigned char **)NewPtr(sizeof(ptr) * my))){
  422.         gResult = memFullErr; return;}
  423.     ptr=(unsigned char *) gStuff->outData;
  424.     for (i=0; i<my; i++){
  425.         o_img.e[i] = ptr;
  426.         ptr += gStuff->outRowBytes;
  427.     }
  428.     mzband = zband * 255.0;
  429.     for (y=0;y < ymax; y++){
  430.         UpdateProgress ((long) y,(long) ymax+nymax/10.0);
  431.         if (TestAbort ()){
  432.             gResult = 1;
  433.             return;
  434.         }
  435.         for (x=0; x < xmax; x++){
  436.             sj = y + wsize;
  437.             for (jj=0,j=y,c=0; j < sj ; j++,jj++){
  438.                 re = m_img.e[jj];
  439.                 pe = &i_img.e[j][x];
  440.                 tpe = &i_img.e[j][x + wsize];
  441.                 for (; pe < tpe; c += *re++ * *pe++);
  442.             }    
  443.             if (c>0 && c<=mzband)
  444.                 c=0;
  445.             if (c<0 && c>=mzband)
  446.                 c=0;
  447.             c_img.e[y+midy][x+midx] = c;
  448.         }
  449.     }
  450.  
  451. /*Detect zero crossings */
  452.     for (y=midy+1,smax=0; y < nymax-1; y++){
  453.         UpdateProgress ((long) ymax+y/10,(long) ymax+nymax/10.0);
  454.         for (x=midx+1; x < nxmax-1; x++){
  455.             short double a,b,c,s;
  456.             c = c_img.e[y][x];
  457.             if (c<0) c = -c;
  458.             s = 0;
  459.             a = c_img.e[y-1][x-1];
  460.             b = c_img.e[y+1][x+1];
  461.             if (a>0 && b<0) s = max(s,a-b);
  462.             else if (a<0 && b>0) s = max(s,b-a);
  463.             a = c_img.e[y-1][x];
  464.             b = c_img.e[y+1][x];
  465.             if (a>0 && b<0) s = max(s,a-b);
  466.             else if (a<0 && b>0) s = max(s,b-a);
  467.             a = c_img.e[y-1][x+1];
  468.             b = c_img.e[y+1][x-1];
  469.             if (a>0 && b<0) s = max(s,a-b);
  470.             else if (a<0 && b>0) s = max(s,b-a);
  471.             a = c_img.e[y][x-1];
  472.             b = c_img.e[y][x+1];
  473.             if (a>0 && b<0) s = max(s,a-b);
  474.             else if (a<0 && b>0) s = max(s,b-a);
  475.             if (s!=0){
  476.                 if (c>s) s=0;
  477.                 else if (sbsflag) s = s - c; else s = 1 - c/s;
  478.             }
  479.             smax = max(s,smax);
  480.             c_img.e[y-2][x-2] = s;
  481.         }
  482.     }
  483.  
  484. /* put it in the ouput image and scale to 0-255 */
  485.     /*printf("Max edge strength = %f¥n",smax);*/
  486.     for (y=midy+1; y < nymax-1; y++)
  487.         for (x=midx+1; x < nxmax-1; x++)
  488.             o_img.e[y][x] = 255.0 - (c_img.e[y-2][x-2]*255.0/smax);
  489.         
  490.     SetRect (&gStuff->inRect, 0, 0, 0, 0); /* let em know we finished */
  491.     gStuff->outRect = gStuff->inRect;
  492. }
  493.  
  494. /*****************************************************************************/
  495.  
  496. /* This routine will always be called if DoStart does not return an error
  497.    (even if DoContinue returns an error or the user aborts the operation).
  498.    This allows the module to perform any needed cleanup.  None is required
  499.    in this example. */
  500.  
  501. void DoFinish (void){
  502.     DisposPtr((Ptr)i_img.e);   /*Free dynamic space used by my img desc array of pts*/
  503.     DisposPtr((Ptr)o_img.e);   /*Free dynamic space used by my img desc array of pts*/
  504.     freeimgr(&m_img);
  505.     freeimgr(&c_img);
  506.  
  507. }
  508.  
  509. /*****************************************************************************/
  510.  
  511. /* Main dispatching routine.  Initializes and sets up the global variables,
  512.    and performs the operation specified by the selector. */
  513.  
  514. pascal void main (short selector, FilterRecordPtr stuff, long *data, short *result){
  515.  
  516.     /* Allow access to global variables */
  517.  
  518.     RememberA0 ();
  519.     SetUpA4 ();
  520.  
  521.     /* Copy the current quickdraw globals into the plug-in local copy */
  522.  
  523.     asm
  524.         {
  525.             MOVE.L    (A5),A0         ; Get address of real quickdraw globals
  526.             SUB.L    #126,A0         ; Move to start
  527.             LEA     randSeed,A1     ; Get address of local copy
  528.             MOVE.W    #64,D0            ; Globals are 65 words long
  529.         @1    MOVE.W    (A0)+,(A1)+     ; Copy a word
  530.             DBF     D0,@1            ; Move to next word
  531.         }
  532.  
  533.     /* Perform the requested operation */
  534.  
  535.     gStuff    = stuff;
  536.     gResult = noErr;
  537.  
  538.     switch (selector)
  539.         {
  540.  
  541.         case filterSelectorAbout:
  542.             DoAbout ();
  543.             break;
  544.  
  545.         case filterSelectorParameters:
  546.             DoParameters ();
  547.             break;
  548.  
  549.         case filterSelectorPrepare:
  550.             DoPrepare ();
  551.             break;
  552.  
  553.         case filterSelectorStart:
  554.             DoStart ();
  555.             break;
  556.  
  557.         case filterSelectorContinue:
  558.             DoContinue ();
  559.             break;
  560.  
  561.         case filterSelectorFinish:
  562.             DoFinish ();
  563.             break;
  564.  
  565.         default:
  566.             gResult = filterBadParameters;
  567.  
  568.         }
  569.  
  570.     *result = gResult;
  571.  
  572.     /* Restore the application's A4 register */
  573.  
  574.     RestoreA4 ();
  575.  
  576.     }
  577.